package model.components.networks.factory;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import model.components.graphs.factory.GraphFactory;
import model.components.graphs.factory.UndirectedGraphFactory;
import model.components.graphs.graph.SparseMultigraphGraph;
import model.components.links.factory.LinksFactory;
import model.components.links.link.Link;
import model.components.nodes.factory.NodesFactory;
import model.components.nodes.node.Node;
import edu.uci.ics.jung.algorithms.cluster.WeakComponentClusterer;
import edu.uci.ics.jung.algorithms.filters.FilterUtils;
import edu.uci.ics.jung.algorithms.generators.random.BarabasiAlbertGenerator;
import edu.uci.ics.jung.algorithms.generators.random.ErdosRenyiGenerator;

public class NetworksFactory
{	
	public static final String RANGE = "Range";
	public static final String PERCENTAGE = "Percentage";
	
	protected SparseMultigraphGraph getBarabasiAlbertGraph( NodesFactory nodesFactory, LinksFactory linksFactory, int minNodesNumber, int maxNodesNumber, int minLinksNumber, int maxLinksNumber )
	{
		int linksNumber = this.randomMinMaxNumber( minLinksNumber, maxLinksNumber );
		int nodesNumber = this.randomMinMaxNumber( minNodesNumber, maxNodesNumber );
		
		BarabasiAlbertGenerator< Node, Link > barabasiAlbertGenerator = new BarabasiAlbertGenerator< Node, Link >( new GraphFactory(), nodesFactory, linksFactory, 1, linksNumber, new HashSet< Node >() );
		barabasiAlbertGenerator.evolveGraph( nodesNumber - 1 );
		
		SparseMultigraphGraph sparseMultigraphGraph = (SparseMultigraphGraph) barabasiAlbertGenerator.create();
		sparseMultigraphGraph.removeUnconnectedNodes();
		
		return sparseMultigraphGraph;
	}
	
	protected SparseMultigraphGraph getErdosRenyiGraph( NodesFactory nodesFactory, LinksFactory linksFactory, int minNodesNumber, int maxNodesNumber, int linksNumberPercentage )
	{
		int nodesNumber = this.randomMinMaxNumber( minNodesNumber, maxNodesNumber );
		double linksNumberProbability = (double) linksNumberPercentage / 100;
		
		ErdosRenyiGenerator< Node, Link > erdosRenyiGenerator = new ErdosRenyiGenerator< Node, Link >( new UndirectedGraphFactory(), nodesFactory, linksFactory, nodesNumber, linksNumberProbability );
		SparseMultigraphGraph sparseMultigraphGraph = (SparseMultigraphGraph) erdosRenyiGenerator.create();
		sparseMultigraphGraph.removeUnconnectedNodes();
		
		Collection< SparseMultigraphGraph > sparseMultigraphGraphs = FilterUtils.createAllInducedSubgraphs( ( new WeakComponentClusterer< Node, Link >() ).transform( sparseMultigraphGraph ), sparseMultigraphGraph ); 
		
		if( sparseMultigraphGraphs.size() > 1 )
		{
			Iterator< SparseMultigraphGraph > sparseMultigraphGraphsIterator = sparseMultigraphGraphs.iterator();
			sparseMultigraphGraph = sparseMultigraphGraphsIterator.next();
			
			while( sparseMultigraphGraphsIterator.hasNext() )
			{
				SparseMultigraphGraph nextSparseMultigraphGraph = sparseMultigraphGraphsIterator.next();
				
				if( nextSparseMultigraphGraph.getVertexCount() > sparseMultigraphGraph.getVertexCount() )
					sparseMultigraphGraph = nextSparseMultigraphGraph;
			}
		}
		
		if( minNodesNumber <= sparseMultigraphGraph.getVertexCount() && sparseMultigraphGraph.getVertexCount() <= maxNodesNumber )
		{
			Iterator< Node > sparseMultigraphGraphVerticesIterator = sparseMultigraphGraph.getVertices().iterator();
			Iterator< Link > sparseMultigraphGraphEdgesIterator = sparseMultigraphGraph.getEdges().iterator();
			
			int nodeCount = 0;
			int linkCount = 0;
			
			while( sparseMultigraphGraphVerticesIterator.hasNext() )
			{
				Node node = sparseMultigraphGraphVerticesIterator.next();
				node.setNumber( nodeCount++ );
				node.setInitialNumber( node.getNumber() );
			}
												
			while( sparseMultigraphGraphEdgesIterator.hasNext() )
			{
				Link link = sparseMultigraphGraphEdgesIterator.next();
				link.setNumber( linkCount++ );
				link.setInitialNumber( link.getNumber() );
			}
			
			nodesFactory.setNodeCount( nodeCount );
			linksFactory.setLinkCount( linkCount );
		}
		else
			sparseMultigraphGraph = this.getErdosRenyiGraph( nodesFactory, linksFactory, minNodesNumber, maxNodesNumber, linksNumberPercentage );
		
		return sparseMultigraphGraph;
	}

	protected int randomMinMaxNumber( int minNumber, int maxNumber )
	{
		return minNumber + (int) ( Math.random() * ( maxNumber - minNumber + 1 ) );
	}
	
}
